package com.pig4cloud.pigx.strategy.util;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.customize.i18n.util.MessageUtils;
import com.pig4cloud.pigx.common.customize.utils.BigDecimalUtils;
import com.pig4cloud.pigx.common.data.resolver.ParamResolver;
import com.pig4cloud.pigx.strategy.constant.StrategyMqConstant;
import com.pig4cloud.pigx.strategy.dto.StrategyContractEmailCloseDTO;
import com.pig4cloud.pigx.strategy.dto.StrategyContractEmailDTO;
import com.pig4cloud.pigx.strategy.dto.StrategyContractEmailErrorDTO;
import com.pig4cloud.pigx.strategy.dto.StrategyContractEmailErrorResolvedDTO;
import com.pig4cloud.pigx.strategy.dto.StrategyContractEmailFuelWarningDTO;
import com.pig4cloud.pigx.strategy.dto.StrategyContractEmailOpenDTO;
import com.pig4cloud.pigx.strategy.dto.StrategyContractEmailPauseDTO;
import com.pig4cloud.pigx.strategy.dto.StrategyContractEmailRestoreDTO;
import com.pig4cloud.pigx.system.constant.EmailTemplateTypeEnum;
import com.pig4cloud.pigx.user.api.feign.DuckweedRemoteSystemService;
import com.pig4cloud.pigx.user.api.feign.UserFeign;
import com.pig4cloud.pigx.user.entity.ArticleInformation;
import com.pig4cloud.pigx.user.entity.User;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.UnsupportedEncodingException;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;
import java.util.Properties;

import static com.pig4cloud.pigx.user.constant.I18nMessages.EMAIL_TEMPLATE_TYPE_DOSE_NOT_EXIST;

/**
 * 邮件发送器
 *
 * @since 2022/9/14 14:52
 */
@Slf4j
@Component
@AllArgsConstructor
public class StrategyEmailSender {

    private final DuckweedRemoteSystemService duckweedRemoteSystemService;
    private final UserFeign userFeign;
    public static Session mailSession = null;

    /**
     * 获取用户信息
     *
     * @param userId 用户id
     * @return {@link User}
     * @since 2022/12/11 16:18
     */
    private User getUser(Long userId) {
        R<User> r = userFeign.getById(userId, SecurityConstants.FROM_IN);
        if (!r.getIsSuccess()) {
            return null;
        }

        return r.getData();
    }

    /**
     * 根据模板编码、语言获得对应的邮箱编码
     *
     * @param templateCode 模板编码
     * @param language     语言
     * @return {@link ArticleInformation}
     * @since 2022/9/14 15:14
     */
    public ArticleInformation getContext(String templateCode, String language) throws MessagingException {
        // 组装模板查询参数
        ArticleInformation condition = new ArticleInformation();
        // 邮件模板编码
        condition.setArticleTypeCode(templateCode);
        // 邮箱模板语言，当前语言为空则返回中文
        condition.setLanguageId(Strings.isEmpty(language) ? "zh_CN" : language);

        R<List<ArticleInformation>> templateR = duckweedRemoteSystemService.getArticleManagementFeign(condition, SecurityConstants.FROM_IN);
        List<ArticleInformation> templateList = templateR.getData();
        // 判断数据获取是否成功
        if (CollectionUtils.isEmpty(templateList)) {
            // 在消息监听中处理失败时，不回滚消息
            throw new MessagingException(MessageUtils.get(EMAIL_TEMPLATE_TYPE_DOSE_NOT_EXIST));
        }

        // 返回下标0的模板
        return templateList.get(0);
    }

    /**
     * 发送邮件
     *
     * @param title   标题
     * @param content 内容
     * @param email   邮箱
     * @since 2022/9/14 15:25
     */
    private void sendEmail(String title, String content, String email) throws MessagingException {
        // 获取邮件会话
        Session mailSession = getMailSession();
        // 创建邮件消息
        MimeMessage message = new MimeMessage(mailSession);

        try {
            // 设置发件人
            InternetAddress form = new InternetAddress(ParamResolver.getStr("MAIL_USER", ""),
                    ParamResolver.getStr("MAIL_SENDER"), "UTF-8");
            message.setFrom(form);

            // 设置收件人
            InternetAddress to = new InternetAddress(email);
            message.setRecipient(Message.RecipientType.TO, to);
            // 设置标题
            message.setSubject(title);
            // 设置内容
            message.setContent(content, "text/html;charset=UTF-8");
            // 发送邮件
            Transport.send(message);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

    }

    /**
     * 获取邮件会话
     *
     * @return {@link Session}
     * @since 2022/9/26 21:26
     */
    private static Session getMailSession() {
        if (!Objects.isNull(mailSession)) {
            return mailSession;
        }

        // 获取配置属性
        final Properties props = getProps();
        // 根据配置属性获取授权信息
        Authenticator authenticator = getAuth(props);

        // 使用环境属性和授权信息，创建邮件会话
        mailSession = Session.getInstance(props, authenticator);

        return mailSession;
    }

    /**
     * 根据配置属性获获取授权信息
     *
     * @param props 配置属性
     * @return {@link Authenticator}
     * @since 2022/9/14 15:24
     */
    private static Authenticator getAuth(Properties props) {
        // 构建授权信息，用于进行SMTP进行身份验证
        return new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                // 用户名、密码
                String userName = props.getProperty("mail.user");
                String password = props.getProperty("mail.password");
                return new PasswordAuthentication(userName, password);
            }
        };
    }

    /**
     * 获取配置属性
     *
     * @return {@link Properties}
     * @since 2022/9/14 15:24
     */
    private static Properties getProps() {
        // 配置发送邮件的环境属性
        final Properties props = new Properties();
        // 发送邮件协议名称
        props.setProperty("mail.transport.protocol", ParamResolver.getStr("MAIL_TRANSPORT_PROTOCOL", "smtp"));
        // 表示SMTP发送邮件，发送服务器需要进行身份验证
        props.put("mail.smtp.auth", ParamResolver.getStr("MAIL_SMTP_AUTH", "true"));
        // 设置邮件服务器主机名
        props.put("mail.smtp.host", ParamResolver.getStr("MAIL_SMTP_HOST", "smtp.qq.com"));
        // smtp登陆的账号、密码 ；需开启smtp登陆
        props.put("mail.user", ParamResolver.getStr("MAIL_USER", ""));
        // 访问SMTP服务时需要提供的密码,不是邮箱登陆密码，一般都有独立smtp的登陆密码
        props.put("mail.password", ParamResolver.getStr("MAIL_PASSWORD", ""));

        // 邮件SMTP时间限制,单位毫秒。这个是有关邮件读取时间长短。默认是无限制。
        props.put("mail.smtp.timeout", 30000);
        // 阿里云25端口默认禁用，使用465SSL接口
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        props.put("mail.smtp.socketFactory.port", "465");
        props.put("mail.smtp.port", "465");
        // 连接时间限制，单位毫秒。是关于与邮件服务器建立连接的时间长短的。默认是无限制
        props.put("mail.smtp.connectiontimeout", 30000);
        // 邮件发送时间限制，单位毫秒。看关发送邮件时内容上传的时间长短。默认同样是无限制。
        props.put("mail.smtp.writetimeout", 30000);


        return props;
    }

    /**
     * 处理发送邮件消息
     *
     * @param dto 消息
     * @since 2022/12/11 16:36
     */
    @RabbitListener(queues = StrategyMqConstant.QUEUE_FANOUT_STRATEGY_EMAIL)
    public void handleMqMsg(StrategyContractEmailDTO dto) {
        // 获取用户信息
        User user = getUser(dto.getUserId());
        if (Objects.isNull(user) || Strings.isBlank(user.getEmail())) {
            return;
        }

        try {
            if (dto instanceof StrategyContractEmailOpenDTO) {
                sendOpen((StrategyContractEmailOpenDTO) dto, user);
            } else if (dto instanceof StrategyContractEmailCloseDTO) {
                sendClose((StrategyContractEmailCloseDTO) dto, user);
            } else if (dto instanceof StrategyContractEmailPauseDTO) {
                sendPause((StrategyContractEmailPauseDTO) dto, user);
            } else if (dto instanceof StrategyContractEmailRestoreDTO) {
                sendRestore((StrategyContractEmailRestoreDTO) dto, user);
            } else if (dto instanceof StrategyContractEmailErrorDTO) {
                sendError((StrategyContractEmailErrorDTO) dto, user);
            } else if (dto instanceof StrategyContractEmailErrorResolvedDTO) {
                sendErrorResolved((StrategyContractEmailErrorResolvedDTO) dto, user);
            } else if (dto instanceof StrategyContractEmailFuelWarningDTO) {
                sendFuelWarning((StrategyContractEmailFuelWarningDTO) dto, user);
            }
        } catch (MessagingException ignore) {
        }
    }

    /**
     * 发送策略开启邮件
     *
     * @param dto  参数
     * @param user 用户
     * @since 2022/9/14 16:02
     */
    public void sendOpen(StrategyContractEmailOpenDTO dto, User user) throws MessagingException {
        // 根据模板编码、语言获得对应的邮箱编码
        ArticleInformation info = getContext(EmailTemplateTypeEnum.OPEN_STRATEGY.getArticleTypeCode(), null);
        String content = info.getTextContent();
        if (Strings.isEmpty(content)) {
            return;
        }

        // 编辑标题信息
        String title = info.getTitle();
        title = title.replace("${time}", dto.getTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        // 编辑模板信息
        content = content.replace("${strategyName}", dto.getStrategyName());

        // 发送邮件
        sendEmail(title, content, user.getEmail());
    }

    /**
     * 发送策略关闭邮件
     *
     * @param dto  参数
     * @param user 用户
     * @since 2022/9/14 16:02
     */
    public void sendClose(StrategyContractEmailCloseDTO dto, User user) throws MessagingException {
        // 根据模板编码、语言获得对应的邮箱编码
        ArticleInformation info = getContext(EmailTemplateTypeEnum.CLOSE_STRATEGY.getArticleTypeCode(), null);
        String content = info.getTextContent();
        if (Strings.isEmpty(content)) {
            return;
        }

        // 编辑标题信息
        String title = info.getTitle();
        title = title.replace("${time}", dto.getTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        // 编辑模板信息
        content = content.replace("${strategyName}", dto.getStrategyName())
                .replace("${reason}", dto.getReason());

        // 发送邮件
        sendEmail(title, content, user.getEmail());
    }

    /**
     * 发送策略暂停邮件
     *
     * @param dto 参数
     * @since 2022/9/14 16:02
     */
    public void sendPause(StrategyContractEmailPauseDTO dto, User user) throws MessagingException {
        // 根据模板编码、语言获得对应的邮箱编码
        ArticleInformation info = getContext(EmailTemplateTypeEnum.SUSPEND_STRATEGY.getArticleTypeCode(), null);
        String content = info.getTextContent();
        if (Strings.isEmpty(content)) {
            return;
        }

        // 编辑标题信息
        String title = info.getTitle();
        title = title.replace("${time}", dto.getTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        // 编辑模板信息
        content = content.replace("${strategyName}", dto.getStrategyName())
                .replace("${reason}", dto.getReason());

        // 发送邮件
        sendEmail(title, content, user.getEmail());
    }

    /**
     * 发送策略恢复邮件
     *
     * @param dto 参数
     * @since 2022/9/14 16:02
     */
    public void sendRestore(StrategyContractEmailRestoreDTO dto, User user) throws MessagingException {
        // 根据模板编码、语言获得对应的邮箱编码
        ArticleInformation info = getContext(EmailTemplateTypeEnum.RECOVERY_STRATEGY.getArticleTypeCode(), null);
        String content = info.getTextContent();
        if (Strings.isEmpty(content)) {
            return;
        }

        // 编辑标题信息
        String title = info.getTitle();
        title = title.replace("${time}", dto.getTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        // 编辑模板信息
        content = content.replace("${strategyName}", dto.getStrategyName())
                .replace("${reason}", dto.getReason());

        // 发送邮件
        sendEmail(title, content, user.getEmail());
    }

    /**
     * 发送策略异常邮件
     *
     * @param dto 参数
     * @since 2022/9/14 16:02
     */
    public void sendError(StrategyContractEmailErrorDTO dto, User user) throws MessagingException {
        // 根据模板编码、语言获得对应的邮箱编码
        ArticleInformation info = getContext(EmailTemplateTypeEnum.ERROR_STRATEGY.getArticleTypeCode(), null);
        String content = info.getTextContent();
        if (Strings.isEmpty(content)) {
            return;
        }

        // 编辑标题信息
        String title = info.getTitle();
        title = title.replace("${time}", dto.getTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        // 编辑模板信息
        content = content.replace("${strategyName}", dto.getStrategyName())
                .replace("${reason}", dto.getReason());

        // 发送邮件
        sendEmail(title, content, user.getEmail());
    }

    /**
     * 发送策略异常解决邮件
     *
     * @param dto 参数
     * @since 2022/9/14 16:02
     */
    public void sendErrorResolved(StrategyContractEmailErrorResolvedDTO dto, User user) throws MessagingException {
        // 根据模板编码、语言获得对应的邮箱编码
        ArticleInformation info = getContext(EmailTemplateTypeEnum.ERROR_RESOLVE_STRATEGY.getArticleTypeCode(), null);
        String content = info.getTextContent();
        if (Strings.isEmpty(content)) {
            return;
        }

        // 编辑标题信息
        String title = info.getTitle();
        title = title.replace("${time}", dto.getTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        // 编辑模板信息
        content = content.replace("${strategyName}", dto.getStrategyName());

        // 发送邮件
        sendEmail(title, content, user.getEmail());
    }

    /**
     * 发送燃油币账户余额告警通知邮件
     *
     * @param dto 参数
     * @since 2022/9/14 16:02
     */
    public void sendFuelWarning(StrategyContractEmailFuelWarningDTO dto, User user) throws MessagingException {
        // 根据模板编码、语言获得对应的邮箱编码
        ArticleInformation info = getContext(EmailTemplateTypeEnum.USER_FUEL_WARNING.getArticleTypeCode(), null);
        String content = info.getTextContent();
        if (Strings.isEmpty(content)) {
            return;
        }

        // 编辑标题信息
        String title = info.getTitle();
        title = title.replace("${time}", dto.getTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        // 编辑模板信息
        content = content.replace("${fuelBalance}", BigDecimalUtils.toStrRemoveExtraZero(dto.getFuelBalance()))
                .replace("${strategyName}", dto.getStrategyName())
                .replace("${fuelFrozen}", BigDecimalUtils.toStrRemoveExtraZero(dto.getFuelFrozen()))
                .replace("${lowFuelRatio}", BigDecimalUtils.toStrRemoveExtraZero(dto.getLowFuelRatio()) + "%");

        // 发送邮件
        sendEmail(title, content, user.getEmail());
    }
}
